﻿using System.IO;
using UnityEngine.AddressableAssets;
using System;
using Newtonsoft.Json;
using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets;
using UnityEditor;
#endif

namespace Super
{
	public static class AssetUtil
	{
		/// <summary>
		/// addressable 加载资源
		/// </summary>
		/// <typeparam name="T">加载资源的类型</typeparam>
		/// <returns></returns>
		public static T ALoadAsset<T>(string path) where T : UnityEngine.Object
		{
#if UNITY_EDITOR
			if (AssetExist(path))
			{
				return AssetDatabase.LoadAssetAtPath<T>(path);
			}
			return null;
#else
			//编辑器模式下不能调用异步方法
			return Addressables.LoadAssetAsync<T>(path).WaitForCompletion();
#endif
		}

		/// <summary>
		/// addressable 加载目录下某种类型资源
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dire"></param>
		/// <returns></returns>
		public static List<T> ALoadAssets<T>(string dire) where T : UnityEngine.Object
		{
#if UNITY_EDITOR
			List<T> result = new List<T>();
			if (AssetExist(dire))
			{
				DirectoryInfo directoryInfo = new DirectoryInfo(dire);
				foreach (FileInfo fileInfo in directoryInfo.GetFiles())
				{
					string relativePath = GlobalUtil.GetAssetsRelativePath(fileInfo.FullName);
					T asset = AssetDatabase.LoadAssetAtPath<T>(relativePath);
					if (asset != null)
					{
						result.Add(asset);
					}
				}
			}
			return result;
#else
			return (List<T>)Addressables.LoadAssetsAsync<T>(dire, null).WaitForCompletion();
#endif
		}

		/// <summary>
		/// addressable 的加载资源,并回调
		/// </summary>
		/// <typeparam name="T">加载资源的类型</typeparam>
		/// <param name="path">加载资源的路径</param>
		/// <param name="action">回调委托</param>
		public static void ALoadAssetAsync<T>(string path, Action<T> action)
		{
			Addressables.LoadAssetAsync<T>(path).Completed += (open) =>
			{
				action(open.Result);
			};
		}

		/// <summary>
		/// 编辑器下判断是否存在AA资源
		/// </summary>
		/// <param name="AName"></param>
		/// <returns></returns>
		public static bool AExist(string AName)
		{
			if (string.IsNullOrEmpty(AName))
			{
				return false;
			}

#if UNITY_EDITOR
			AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
			foreach (var group in addressableSettings.groups)
			{
				foreach (var item in group.entries)
				{
					if (item.address == AName)
					{
						return true;
					}
				}
			}
			return false;
#else
			return true;
#endif
		}

		/// <summary>
		/// 编辑器模式下获取AA资源的AssetPath
		/// 默认情况下AName应该和AssetPath保持一致。
		/// </summary>
		/// <param name="AName"></param>
		/// <param name="groupName"></param>
		/// <returns></returns>
		public static string GetAAssetPath(string AName, string groupName = null)
		{
#if UNITY_EDITOR
			AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
			if (!string.IsNullOrEmpty(groupName))
			{
				foreach (var item in addressableSettings.FindGroup(groupName).entries)
				{
					if (item.address == AName)
					{
						return item.AssetPath;
					}
				}
				return "";
			}

			foreach (var curGroup in addressableSettings.groups)
			{
				foreach (var item in curGroup.entries)
				{
					if (item.address == AName)
					{
						return item.AssetPath;
					}
				}
			}
			return "";
#else
			return "";
#endif
		}

		/// <summary>
		/// 编辑器下判断是否存在资源
		/// </summary>
		/// <param name="assetPath"></param>
		/// <returns></returns>
		public static bool AssetExist(string assetPath)
		{
#if UNITY_EDITOR
			string absolutePath = GlobalUtil.GetAbsolutePath(assetPath);
			return File.Exists(absolutePath) || Directory.Exists(absolutePath);
#else
			return true;
#endif
		}

		/// <summary>
		/// addressable 创建或可寻址资源到Group中
		/// 默认assetPath为资源的寻址地址
		/// </summary>
		/// <param name="GroupName">资源的组名</param>
		/// <param name="assetPath">资源的寻址地址</param>
		public static void ACreateOrMove(string GroupName, string assetPath)
		{
#if UNITY_EDITOR
			assetPath = GlobalUtil.GetAssetsRelativePath(assetPath);
			string guiId = AssetDatabase.AssetPathToGUID(assetPath);
			AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
			AddressableAssetEntry assetEntry = addressableSettings.FindAssetEntry(guiId);
			if (assetEntry != null && assetEntry.parentGroup.Name == GroupName)
			{
				return;	//已存在就不用处理了
			}

			AddressableAssetGroup customGroup = addressableSettings.FindGroup(GroupName);
			if (customGroup == null)
			{
				customGroup = addressableSettings.CreateGroup(GroupName, false, false, false, null, typeof(BundledAssetGroupSchema));
			}


			addressableSettings.CreateOrMoveEntry(guiId, customGroup);
			EditorUtility.SetDirty(addressableSettings);
			AssetDatabase.Refresh();
			LogUtil.Log(LogType.Normal, LogCategory.Create, $"{assetPath}移动到AddressGroup：{GroupName}AddressGroup中");
#endif
		}

		/// <summary>
		/// 保存游戏数据
		/// </summary>
		/// <typeparam name="T">需要保存数据的类型 某个类</typeparam>
		/// <param name="path">保存的资源路径例如"RanKData/TestScript.sav"</param>
		/// <param name="data">保存的数据</param>
		public static void SavePersistentData<T>(string path, T data)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = JsonConvert.SerializeObject(data);

			SavePersistentData(directory, fileName, saveText);
		}

		/// <summary>
		/// 以RSA方式加密，保存数据
		/// </summary>
		/// <typeparam name="T">需要保存数据的类型 某个类</typeparam>
		/// <param name="path">保存的资源路径例如"RanKData/TestScript.sav"</param>
		/// <param name="data">保存的数据</param>
		public static void SavePersistentEncryptData<T>(string path, T data)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = JsonConvert.SerializeObject(data);
			string encryptText = EncryptUtil.Encrypt(saveText, FWConfig.PublicKey_RSAXml);

			SavePersistentData(directory, fileName, encryptText);
		}

		private static void SavePersistentData(string directory, string fileName, string text)
		{
			directory = GlobalUtil.GetPersistentDataPath(directory);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
			}

			StreamWriter sw = new StreamWriter(directory + "/" + fileName);
			sw.Write(text);
			sw.Flush();
			sw.Close();
		}

		/// <summary>
		/// 读取游戏数据
		/// </summary>
		/// <typeparam name="T">资源类型</typeparam>
		/// <param name="path">读取的资源路径例如"RanKData/TestScript.cs"</param>
		/// <returns>返回保存的对象</returns>
		public static T LoadPersistentData<T>(string path)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = LoadPersistentData(directory, fileName);

			if (String.IsNullOrEmpty(saveText))
				return default(T);

			T data = JsonConvert.DeserializeObject<T>(saveText);
			return data;
		}

		/// <summary>
		/// 读取游戏数据,并且以RSA算法进行解密
		/// </summary>
		/// <typeparam name="T">资源类型</typeparam>
		/// <param name="path">读取的资源路径例如"RanKData/TestScript.cs"</param>
		/// <returns>返回保存的对象</returns>
		public static T LoadPersistentEncryptData<T>(string path)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string encryptText = LoadPersistentData(directory, fileName);
			if (String.IsNullOrEmpty(encryptText))
				return default(T);


			string decryptedText = EncryptUtil.Decrypt(encryptText, FWConfig.PrivateKey_RSAXml);
			T data = JsonConvert.DeserializeObject<T>(decryptedText);

			return data;
		}

		private static string LoadPersistentData(string directory, string fileName)
		{
			directory = GlobalUtil.GetPersistentDataPath(directory);
			string saveText = "";
			if (File.Exists(directory + "/" + fileName))
			{
				StreamReader sr = new StreamReader(directory + "/" + fileName);
				saveText = sr.ReadToEnd();
				sr.Close();
			}

			return saveText;
		}

		/// <summary>
		/// 保存文本，脚本内容
		/// 资源路径是Assets开头的相对路径
		/// </summary>
		/// <param name="path">文本资源路径 例如Assets/FrameWork/ExcelTool/CustomExcelDataClass/Sheet2_SO.cs</param>
		/// <param name="content">文本内容</param>
		public static void CreateFile(string path, string content)
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				LogUtil.Log(LogType.Normal, LogCategory.Create, $"创建{directory}目录");
			}
			StreamWriter sw = new StreamWriter(path);
			sw.Write(content);
			sw.Flush();
			sw.Close();
			AssetDatabase.Refresh();
		}

		public static bool TryCreatDirectory(string path)
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				LogUtil.Log(LogType.Normal, LogCategory.Create, $"创建{directory}目录");
				return true;
			}
			return false;
		}

		/// <summary>
		/// 不存在目录或文件时创建，创建文件后返回true
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		public static bool TryCreatDirectoryAndFile(string path, string content = "")
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			bool isCreated = false;
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				isCreated = true;
				LogUtil.Log(LogType.Normal, LogCategory.Create, $"创建{directory}目录");
			}
			if (!File.Exists(path))
			{
				CreateFile(path, content);
				isCreated = true;
				LogUtil.Log(LogType.Normal, LogCategory.Create, $"创建{path}文件");
			}

			return isCreated;
		}

		public static void SaveToAsset<T>(string assetPath, T data)
		{
			string saveText = JsonConvert.SerializeObject(data);
			CreateFile(assetPath, saveText);
		}

		public static T LoadByAsset<T>(string AName)
		{
			if (!AExist(AName))
			{
				return default(T);
			}
			string path = GlobalUtil.GetAbsolutePath(AName);
			string saveText = "";
			if (File.Exists(path))
			{
				StreamReader sr = new StreamReader(path);
				saveText = sr.ReadToEnd();
				sr.Close();
			}

			if (string.IsNullOrEmpty(saveText))
			{
				return default(T);
			}


			T data = JsonConvert.DeserializeObject<T>(saveText);
			return data;
		}
	}

}
